var fs = require('fs');
var toDuration = function(duration) {

    return "PT" + parseInt(duration / 3600) + "H" + parseInt((duration % 3600) / 60) + "M" + duration % 3600 + "S";
};
String.prototype.hashCode = function() {
    //Merci stackOverFlow
    var hash = 0, i, chr, len;
    if (this.length == 0)
        return hash;
    for (i = 0, len = this.length; i < len; i++) {
        chr = this.charCodeAt(i);
        hash = ((hash << 5) - hash) + chr;
        hash |= 0; // Convert to 32bit integer
    }
    return hash;
};
var isEmpty = function(obj) {
    for (var prop in obj) {
        if (obj.hasOwnProperty(prop)) {
            return false;
        }
    }
    return true;
};
var DateDebut;
Date.prototype.toIcal = function() {
    var tmp = new Date(this.getTime() + (3600 * 1000));
    return tmp.toISOString().replace(/-|:|\..*/g, "");
};
String.prototype.InterArray = function(splitter) {
    splitter = splitter === undefined ? ";" : splitter;
    var heuresDispo = this.split(splitter);
    var tmp = [];
    for (var i = 0; i < heuresDispo.length; i++) {
        tmp = interToArray(heuresDispo[i], "-", tmp);
    }
    return tmp;
};
var interToArray = function(interval, splitter, array) {
    var tmp = array;
    var split = interval.split(splitter);
    for (var i = parseInt(split[0]); i < parseInt(split[1]); i++) {
        tmp.push(i);
    }
    return tmp;
};
Array.prototype.contains = function(index, method) {
    if (method !== undefined) {
        for (var i = 0; i < this.length; i++) {
            if (this[i][method]() === index[method]()) {
                return true;

            }
        }
    }
    else {
        for (var i = 0; i < this.length; i++) {
            if (this[i] === index) {
                return true;
            }
        }
    }
    return false;
};
var RDV = function() {
    var _id = 0;
    var _lieu = 0;
    var _typeInter = "";
    var _heureDebut;
    var _heureFin;
    var proprietaire;
    var _summary;
    var _location;
    var infoSetted = false;
    var _isDemiHeure;
    var _proprietaire;
    return{
        setDemiHeure: function(isDemiHeure) {
            _isDemiHeure = isDemiHeure;
            return this;
        },
        getDemiHeure: function() {
            return _isDemiHeure;
        },
        getId: function() {
            return _typeInter.hashCode();
        },
        constructor: function(heureDebut, heureFin, typeInter, proprietaire) {
            _heureDebut = heureDebut;
            _heureFin = heureFin;
            _typeInter = typeInter;
            _proprietaire = proprietaire;

            return this;
        },
        getHeureFin: function() {
            return _heureFin;
        },
        setHeureDebut: function(heureDebut) {
            _heureDebut = heureDebut;
        },
        setHeureFin: function(heureFin) {
            _heureFin = heureFin;
        },
        infoManquantes: function() {
            if (!infoSetted) {
                console.log("Il manque des informations pour le RDV " + this.toString());
            }
            infoSetted = true;
            return true;
        },
        toString: function() {
            return _typeInter + " de " + _heureDebut + " à " + _heureFin;
        },
        init: function() {
            infoSetted = false;
            _summary = _summary === undefined ? this.infoManquantes() && readline.question("Description: ") : _summary;
            _typeInter = _typeInter === undefined ? this.infoManquantes() && readline.question("Nom de l'interventions ") : _typeInter;
            _location = _location === undefined ? this.infoManquantes() && readline.question("Lieu ") : _location;
            _proprietaire = _proprietaire === undefined ? this.infoManquantes() && readline.question("Proprietaire") : _proprietaire;
        },
        toIcal: function(proprietaire) {
            this.init();
            _proprietaire = _proprietaire !== undefined ? _proprietaire : proprietaire;
            var str = "BEGIN:VEVENT\n";
            str += "DTSTAMP:" + new Date().toIcal() + "\n";
            str += "ORGANIZER:MAILTO:" + _proprietaire + "\n";
            str += "DTSTART:" + _heureDebut.toIcal() + "\n";
            str += "DTEND:" + _heureFin.toIcal() + "\n";
            str += "DURATION:" + toDuration(((_heureFin.getTime() - _heureDebut.getTime()) / 1000)) + "\n";
            str += "SUMMARY:" + _summary + "\n";
            str += "LOCATION:" + _location + "\n";
            str += "DESCRIPTION:";
            str += _typeInter + "\n";
            str += "END:VEVENT" + "\n";

            return str;
        },
        lieu: function() {
            return _lieu;
        },
        typeInter: function() {
            return _typeInter;
        }
    };
};
var Heure = function(estDisponible) {
    var _value = 0;
    var _rdv;
    var _estDisponible = estDisponible;
    var _isDemiHeure;
    return {
        setDemiHeure: function(isDemiHeure) {
            _isDemiHeure = isDemiHeure;
            return this;
        },
        getDemiHeure: function() {
            return _isDemiHeure;
        },
        setDisponible: function(disponible) {
            _estDisponible = disponible;
        },
        getDisponible: function() {
            return _estDisponible;
        },
        setRDV: function(rdv) {
            _rdv = rdv;
        },
        setValue: function(value) {
            _value = value;
            return this;
        },
        getRDV: function() {
            return _rdv;
        }
    };
};
var Journee = function(interval) {
    var _heures = [];
    var _rdv = [];

    if (interval !== undefined) {
        for (var i = 0; i < 48; i++) {
            var demi = i % 2 === 0;
            if (interval.contains(i))
            {
                _heures.push(new Heure(true).setValue(i / 2).setDemiHeure(demi));
            }
            else {
                _heures.push(new Heure(false).setValue(i / 2).setDemiHeure(demi));
            }
        }
    }
    else {
        for (var i = 0; i < 48; i++) {
            _heures.push(new Heure().setValue(i));
        }
    }

    return {
        getNbrRdv: function() {
            this.heuresToRdv();
            return _rdv.length;
        },
        heuresToRdv: function(currentJour) {
            _rdv = [];
            for (var i = 0, rdv = _heures[0].getRDV(); i < _heures.length; i++) {
                var heureFin;
                rdv = _heures[i].getRDV();
                if (!isEmpty(rdv)) {
                    var currentDate = DateDebut.getTime();
                    var heureDebut = currentDate + (24 * 3600 * 1000 * currentJour) + (60 * (parseInt(i / 2) + 1) * 60 * 1000) + ((i % 2) * 30 * 60 * 1000);
                    rdv.setHeureDebut(new Date(heureDebut));
                    heureFin = heureDebut + parseInt(((3600 * 1000) / 2));
                    rdv.setHeureFin(new Date(heureFin));
                    _rdv.push(rdv);
                }
            }
        },
        toIcal: function(_proprietaire) {
            var str = "";
            //this.heuresToRdv();console.log(_rdv);
            for (var i = 0; i < _rdv.length; i++) {

                str += _rdv[i].toIcal(_proprietaire);
            }
            return str;
        },
        getHeures: function() {
            return _heures;
        }
        ,
        setHeures: function(heures) {
            _heures = heures;
        },
        ajoutRDV: function(heureDebut, heureFin) {
        }
        ,
        setJourOff: function() {
            for (var i = 0; i < _heures.length; i++) {
                _heures[i].setDisponible(false);
            }
        }
    };
};
var Semaine = function(interval) {
    var _nbJoursTravaille = 0;
    var _jours = [];
    var _interval = interval;
    return {
        getNombresIntervention: function() {
            var tmp = 0;
            for (var i = 0; i < _jours.length; i++) {
                tmp += _jours[i].getNbrRdv();
            }
            return tmp;
        },
        toIcal: function(_proprietaire) {
            var str = "";
            for (var i = 0; i < _jours.length; i++) {
                _jours[i].heuresToRdv(i);
            }
            for (var i = 0; i < _jours.length; i++) {
                str += _jours[i].toIcal(_proprietaire);
            }

            return str;
        },
        constructor: function(nbJoursTravaille) {
            _nbJoursTravaille = nbJoursTravaille;

            this.setJours(7, undefined);
            return this;
        },
        setDispo: function(jours) {
            _jours = jours;
        },
        getJours: function() {
            return _jours;
        },
        setJours: function(nbjours, jourFerie) {
            _jours = [];
            _nbJoursTravaille = nbjours;
            for (var i = 0; i < _nbJoursTravaille; i++) {

                _jours.push(new Journee(_interval));
            }
            if (jourFerie != undefined) {

                for (var i = 0; i < _nbJoursTravaille; i++) {
                    if (jourFerie.contains(i)) {
                        _jours[i].setJourOff();
                    }
                }
            }

        },
        //Deprecated
        ajoutRDV: function(jour, heureDebut, heureFin) {
        },
    };
};

var EdT = function() {
    var _nbJoursTravaille = 0;
    var _semaine;
    var _proprietaire;
    var _nombresIntervention = 0;
    return {
        setNombresIntervention: function() {
            _nombresIntervention = _semaine.getNombresIntervention();
            return _nombresIntervention;
        },
        addRdvConsole: function() {
            var heureDebut = readline.question("\n Demi Heure de debut?(0 à 48) ");
            var heureFin = readline.question("Demi Heure de fin ? (" + heureDebut + " à 48) ");
            var jour = readline.question("Jour d'intervention ? (Lundi : 0; Dimanche : 6) ");
            var typeInter = readline.question("Type d'intervention ");
            this.addRDV(heureDebut, heureFin, jour, typeInter);

            //TODO : regler le probleme de this.toString();



            toString(); //Problème : cette fonction ne renvoit rien !
            return this;
        },
        addRDV: function(heureDebut, heureFin, jour, typeInter, proprietaire) {
            for (var i = heureDebut; i < heureFin; i++) {
                var rdv = new RDV().constructor(heureDebut, heureFin, typeInter, proprietaire);
                var heure = _semaine.getJours()[jour].getHeures()[i];
                if (!heure.getDisponible())
                {
                    console.log("\n\n\n\nImpossible : il y a des indisponibilites dans les horaires pour le rdv :" + typeInter + " commencant à " + parseInt(heureDebut / 2) + "h" + parseInt((heureDebut % 2) * 30) + " et terminant à " + parseInt(heureFin / 2) + "h" + parseInt((heureFin % 2) * 30) + " le jour N°" + jour);
                    //TODO : Resoudre les problèmes d'incompatibilite
                    return this.addRdvConsole();

                }
                heure.setRDV(rdv);
            }
            return this;
        },
        toIcal: function() {

            var str = "";
            //Christopher Olivier Remi Yamine = CORY
            str += "BEGIN:VCALENDAR\nMETHOD:PUBLISH\nVERSION:2.0\nPRODID:CORY\n";
            str += _semaine.toIcal(_proprietaire);
            str += "END:VCALENDAR";
            return str;
        },
        constructor: function(proprietaire) {
            _proprietaire = proprietaire;

            return this;
        },
        getSemaine: function() {
            return _semaine;
        }
        ,
        setProprietaire: function(proprietaire) {
            _proprietaire = proprietaire;
            return this;
        },
        getProprietaire: function() {
            return _proprietaire;
        },
        setSemaine: function(semaine) {
            _semaine = semaine;
        },
        toString: function() {
            var str = "";
            str += "Voici l'emploi du temps de " + _proprietaire + ":\n";
            str += "Il a fait " + this.setNombresIntervention() + " interventions\n";
            for (var i = 0; i < 7; i++) {
                var semaine = this.getSemaine();
                str += semaine.getJours()[i] + " : ";
                for (var j = 0; j < 48; j++) {
                    if (semaine.getJours()[i].getHeures()[j].getDisponible() == false) {
                        str += semaine.getJours()[i].getHeures()[j] + " ";
                    }
                }
                str += "\n";
            }
            str += "";
            return str;
        },
        compareEDT: function(EDT) {

            var string = "";
            var nbDispo = 0;
            if (!Array.isArray(EDT)) {
                var tmp = [];
                tmp.push(EDT);
                EDT = tmp;
            }
            for (var i = 0; i < 7; i++) {
                for (var j = 0; j < 24; j++) {
                    string += "\nJour : " + i + " Heures :" + j;
                    //  console.log(this.getSemaine().getJours()[i].getHeures()[j].getDisponible());
                    if (this.getSemaine().getJours()[i].getHeures()[j].getDisponible())
                    {

                        string += "\n\t" + this.getProprietaire();
                        nbDispo++;
                    }
                    for (var k = 0; k < EDT.length; k++) {
                        if (EDT[k].getSemaine().getJours()[i].getHeures()[j].getDisponible()) {
                            nbDispo++;
                            string += "\n\t" + EDT[k].getProprietaire();
                        }
                    }

                    if (nbDispo > 0) {
                        string += "\n Nombres de disponibles : " + nbDispo;
                    }
                    nbDispo = 0;
                }
            }
            console.log(string);
            return string;
        }
    };
};
EdT.prototype.toString = function() {
    var string = "";
    for (var i = 0; i < 7; i++) {
        for (var j = 0, heureCourante = this.getSemaine().getJours()[i].getHeures()[j]; j < 24; j++) {

            //  console.log(this.getSemaine().getJours()[i].getHeures()[j].getDisponible());
            if (!heureCourante.getDisponible() && heureCourante.getRDV())
            {
                string += "\nJour : " + i + " Heures :" + j;
                string += "\n\t" + this.getProprietaire();
            }

        }
    }
    return string;
};
var Employe = function() {
    var _id;
    var _nom;
    var _prenom;
    var _metier;
    var _tel;
    var _edT;

    return {
        setIdToInt: function() {
            _id = parseInt(_id);
            return this;
        },
        constructor: function(id, nom, prenom, metier, tel) {
            _id = id;
            _nom = nom;
            _prenom = prenom;
            _metier = metier;
            _tel = tel;

            _edT = new EdT().constructor(_nom + " " + _prenom);

            return this;
        },
        setDisponibilite: function(jours, rl, heuresDispo, joursFerie, heureFerie) {
            var semaine;

            if (rl !== undefined) {
                heuresDispo = rl.question('Intervalles de disponibilite pour la semaine :(8-12;14-18)[Entree] ');
            }
            if (heuresDispo == "") {
                heuresDispo = "16-24;28-36";
            }
            console.log("Heures de disponibilites : " + heuresDispo);
            heuresDispo = heuresDispo.InterArray();
            semaine = new Semaine(heuresDispo).constructor();
            semaine.setJours(jours);
            jours = semaine.getJours();
            for (var i = 0; i < jours.length; i++) {
                jours[i] = this.setJourDispo(jours[i], heuresDispo, true);
            }
            if (rl !== undefined) {
                joursFerie = rl.question('Entrez le [numero] des jours avec des indisponibilites, [separe] par des ;(Lundi : 0 , Dimanche : 6)[Entree] ');
            }
            if (joursFerie !== "") {
                joursFerie = joursFerie.split(";");
                for (var i = 0; i < joursFerie.length; i++) {
                    if (rl !== undefined) {
                        heureFerie = rl.question('Entrez un ou plusieurs intervalle d\'indisponibilites pour le jour ' + joursFerie[i] + ':(0-24;24-48)[Entree] ');
                    }
                    if (heureFerie == "") {
                        heureFerie = "0-24;24-48";
                    }
                    heureFerie = heureFerie.InterArray(";");
                    jours[joursFerie[i]] = this.setJourDispo(jours[joursFerie[i]], heureFerie, false);
                    heureFerie = "";
                }
            }
            this.getEdT().setSemaine(semaine);

            return this;
        },
        setJourDispo: function(jour, intervalle, dispo) {

            var heures = jour.getHeures();
            for (var i = 0; i < intervalle.length; i++) {
                // console.log("Setting "+intervalle[i]+"to "+dispo);
                heures[intervalle[i]].setDisponible(dispo);
            }
            jour.setHeures(heures);
            return jour;
        },
        getId: function() {
            return _id;
        },
        getNom: function() {
            return _nom;
        },
        getPrenom: function() {
            return _prenom;
        },
        getMetier: function() {
            return _metier;
        },
        getTel: function() {
            return _tel;
        },
        getEdT: function() {

            return _edT;
        },
        setId: function(id) {
            _id = id;
            return this;
        },
        setNom: function(nom) {
            _nom = nom;
            return this;
        },
        setPrenom: function(prenom) {
            _prenom = prenom;
            return this;
        },
        setMetier: function(metier) {
            _metier = metier;
            return this;
        },
        setTel: function(tel) {
            _tel = tel;
            return this;
        },
        setSemaine: function(semaine) {
            _semaine = semaine;
            return this;
        },
        setEdt: function(edt) {
            _edt = edt;

            return this;
        },
    };
};
var ecrireFichier = function(str, fichier) {
    var fs = require("fs");
    fichier = fichier === undefined ? "edt.ics" : fichier;
    fs.writeFileSync(readline.question("Nom de fichier?[" + fichier + "] ") || fichier, str, "UTF-8");
};

//Menu affichage des fonctions
var displayMenu = function() {
    var choix = undefined;
    while (choix !== 0) {
        console.log("\n\n=== MENU ===\n\n");
        console.log("1 - Creer un nouveau RDV");
        console.log("2 - Identifier les disponibilites d'un emploi du temps d'un employe");
        console.log("3 - Comparer les emplois du temps de plusieurs employes");
        console.log("4 - Afficher les informations d'un RDV");
        console.log("5 - Visualiser les donnees annexes de l'emploi du temps\n");
        console.log("6 - Transferer un fichier CSV au format iCal\n");
        console.log("0 - Quitter\n");
        choix = readline.question("Entrez le numero correspondant à votre choix : ");
        choix = parseInt(choix);
        if (choix < 0 || choix > 6) {
            console.log("\nChoix incorrect, veuillez recommencez !\n");
        } else {
            menu(choix);
        }
    }
};


//Choix d'une fonction dans le menu
var menu = function(_choix) {
    var emp1 = 0;
    var emp2 = 0;

    switch (_choix) {
        case 0 :
            console.log("\nVous avez quitte le programme !\n");
            break;
        case 1 :
            employes === undefined ? creerEmployes() : undefined;
            console.log("------- Creer un nouveau RDV -------");
            emp1 = rechercherEmploye();
            if (emp1 !== undefined)
            {
                emp1.getEdT().addRdvConsole();
            } else {
                displayMenu();
            }
            break;
        case 2 :


            employes === undefined ? creerEmployes() : undefined;
            console.log("------- Identifier les disponibilites d'un emploi du temps d'un employe -------");
            emp1 = rechercherEmploye();
            emp1.setDisponibilite(7, readline);
            break;
        case 3 :
            employes === undefined ? creerEmployes() : undefined;
            console.log("------- Comparer les emplois du temps de plusieurs employes -------");
            if (employes.length >= 2) {
                var nombreAComparer = readline.question("Combien d'emploi du temps voulez comparer");

                if (nombreAComparer < 2 || nombreAComparer > employes.length) {
                    console.log("\nVous devez avoir au moins 2 employes enregistres pour comparer des emplois du temps.\n");
                } else {
                    var tabTmp = [];
                    for (var i = 1; i < nombreAComparer; i++) {
                        console.log("\n- " + i + "eme employe - ");
                        tabTmp.push(rechercherEmploye().getEdT());
                    }
                }
                console.log("\n- " + i + "eme employe - ");
                ecrireFichier(rechercherEmploye().getEdT().compareEDT(tabTmp), "Comparaison.txt");
                console.log("Les EdT ont ete compare dans le fichier Comparaison.txt");
            } else {
                console.log("\nVous devez avoir au moins 2 employes enregistres pour comparer des emplois du temps.\n");
            }
            break;
        case 4 :
            employes === undefined ? creerEmployes() : undefined;
            console.log("------- Afficher les informations d'un RDV -------");
            emp1 = rechercherEmploye();
            console.log(emp1.getEdT().toString());
            break;
        case 5 :
            employes === undefined ? creerEmployes() : undefined;
            console.log("------- Visualiser les donnees annexes de l'emploi du temps -------");
            emp1 = rechercherEmploye();

            // Appeler fonction permettant de visualiser les donnees annexes d'un EDT
            break;
        case 6:
            console.log("Attention, la date de debut n'a pas ete change");
            console.log("------- Transferer un fichier CSV au format iCal -------");
            lanceCSV();
            break;
        default :
            console.log("Erreur !\n");
    }
};

var readline = require('readline-sync');
var id = 0;
var nom = 0;
var prenom = 0;
var metier = 0;
var tel = 0;
var employes = undefined;
var DateDebut = new Date(2014, 11, 1, 0, 0, 0, 0);
var globalEDT = new Semaine();
globalEDT.setJours(7);
var rechercherEmploye = function() {
    var emp = 0;
    id = readline.question("\nEntrez l'identifiant de l'employe : ");
    id = parseInt(id);
    for (var employeTmp in employes) {
        if (employes[employeTmp].getId() === id) {
            return employes[employeTmp];
        }
    }
    return undefined;
};

var choix = 0;


var choisirNombreEmployes = function() {
    var nbreEDT = 0;
    while (nbreEDT < 1 || nbreEDT > 10) {
        nbreEDT = readline.question("\nInitialisation du tableau d'employees\nPour combien d'employes souhaitez-vous creer un emploi du temps ? ");
        if (nbreEDT < 1 || nbreEDT > 10) {
            console.log("Le nombre d'employes doit être compris entre 1 et 10.\n");
        }
    }
    nbreEDT = parseInt(nbreEDT);
    return nbreEDT;
};

var creerEmployes = function() {
    var nbreEDT = choisirNombreEmployes();
    employes = [];
    if (!isNaN(nbreEDT)) {
        for (i = 0; i < nbreEDT; i++) {
            console.log("\nEntrez les informations relatives à l'employe " + (i + 1) + ".");
            id = readline.question("\n\nIdentifiant : ");
            nom = readline.question("Nom : ");
            prenom = readline.question("Prenom : ");
            metier = readline.question("Metier : ");
            tel = readline.question("Telephone : ");
            var employe = new Employe().constructor(id, nom, prenom, metier, tel).setIdToInt();
            while (employes[id] !== undefined || isNaN(parseInt(id))||parseInt(id) < 0) {
                console.log("L'id de l'employe est invalide");
                id = readline.question("Id pour l'employe:\n");
            }
            employes[id] = employe;
            employes[id].setDisponibilite(7, readline);
        }
        
    }
};


displayMenu();




/*
 //TODO : DIMANCHE
 
 //employe.getEdT().compareEDT(employe.getEdT());
 //TODO : Write files
 
 ecrireFichier(employe3.getEdT().toIcal());
 console.log(employe3.getEdT().toIcal());
 //RMQ : Utilisation peu conviviale
 //RMQ : Emploi du temps : comparaison : Qui est dispo?
 */
lanceCSV();


function lanceCSV() {
    var csv = readline.question("Quel est le fichier csv que vous souhaitez importer ?  ");
    importCSV(csv);
}

function importCSV(myArgs) {
//var myArgs = process.argv.slice(1);
    var input = [];
    data = fs.readFileSync(myArgs, 'utf8');
    var tmp = data.split("\r\n");
    var employe = new Employe().constructor();
    employe.setDisponibilite(7, readline);
    for (var i = 0; i < tmp.length; i++) {
        input.push(tmp[i].split(";"));
    }
    //ATTENTION VERIFIER QU'IL Y A BIEN UNE LIGNE DES JOURNEES DE LA SEMAINE
    for (var i = 1; i < input.length; i++) {
        //ATTENTION  :  VERIFIER QU'IL Y A UN POINT VIRGULE A LA FIN DE CHAQUE LIGNE cf BNF
        for (var j = 0; j < input[i].length - 1/* SUPPRESSION DE LA DERNIERE CASE DU TABLEAU */; j++) {
            if (input[i][j] !== "vide") {
                var propEtType = input[i][j].replace("\(", "\n").split("\n");
                employe.getEdT().addRDV(i, i + 1, j, propEtType[0], propEtType[1].slice(0, propEtType[1].length - 1));

            }
        }
    }
    console.log(employe.getEdT().toIcal());
    ecrireFichier(employe.getEdT().toIcal());
}
//TODO : Envoyer en emails & construire une fusee.